<template>
  <table
    cellspacing="0"
    cellpadding="0"
    border="0"
    style="table-layout: fixed; border-collapse: separate; border-spacing: 0; width: auto"
  >
    <colgroup>
      <col
        name="selection"
        :width="selection.width"
        v-if="selection.visible"
        :style="{ minWidth: `${selection.width}px` }"
      />
      <col
        v-for="column in columns"
        :key="column.prop"
        :name="column.prop"
        :width="column.width || 'auto'"
        :style="{ minWidth: `${column.minWidth || column.width}px` }"
      />
    </colgroup>
    <tbody style="overflow-y: auto" ref="sortableTbody">
      <tr class="table_body__row create_row no-drag" v-show="isCreate">
        <td></td>
        <td :style="getCreateStyle()">
          <div class="create_row__button" @click.stop="handleCreate">
            <el-icon class="el-icon--left"><Plus /></el-icon>
            <span>快速创建</span>
          </div>
        </td>
        <td :colspan="createRowSpan - 2"></td>
      </tr>
      <tr v-for="(row, rowIndex) in data" :key="row.id" :class="getRowClass(row, rowIndex)" class="table_body__row">
        <td
          style="text-align: left; padding: 0 10px"
          v-if="selection.visible"
          :style="getSelectionStyle()"
          :class="getSelectionClass(row, rowIndex)"
          class="drag-handle"
        >
          <el-checkbox v-model="row.checked" @change="handleSelect(row)"></el-checkbox>
          <span class="handle-span">
            <el-icon class="more-filled"><MoreFilled /></el-icon>
          </span>
        </td>
        <td
          v-for="column in columns"
          :key="column.prop"
          :style="getColStyle(column)"
          :class="getColClass(row, rowIndex, column)"
        >
          <slot :name="column.prop" :row="row" :column="column" :$index="rowIndex">
            {{ row[column.prop] }}
          </slot>
        </td>
      </tr>
    </tbody>
  </table>
</template>

<script>
import { Plus, MoreFilled } from '@element-plus/icons-vue';
import Sortable from 'sortablejs';

export default {
  name: 'TableBody',
  components: {
    Plus,
    MoreFilled,
  },
  props: {
    columns: {
      type: Array,
      required: true,
    },
    data: {
      type: Array,
      required: true,
    },
    rowClassName: {
      type: [String, Function],
      default: '',
    },
    selection: {
      type: Object,
      default: () => {
        return {
          width: 55,
          visible: true,
        };
      },
    },
    fixdColumns: {
      type: Object,
      default: () => {
        return {};
      },
    },
    isSrcoll: {
      type: Boolean,
      default: false,
    },
  },
  computed: {
    // 创建行列数
    createRowSpan() {
      if (this.selection.visible) {
        return this.columns.length + 1;
      }
      return this.columns.length;
    },
    isFixed() {
      return Object.keys(this.fixdColumns).length > 0;
    },
  },
  data() {
    return {
      isCreate: true,
      sortableInstance: null,
    };
  },
  created() {},
  mounted() {
    // 初始化 Sortable
    this.initSortable();
  },
  beforeDestroy() {
    // 销毁 Sortable 实例
    if (this.sortableInstance) {
      this.sortableInstance.destroy();
    }
  },
  methods: {
    initSortable() {
      const tbody = this.$refs.sortableTbody;

      this.sortableInstance = Sortable.create(tbody, {
        animation: 150,
        filter: '.no-drag',
        handle: '.drag-handle',
        onMove: function (evt) {
          // 过滤掉的元素阻止移动
          return evt.related.className.indexOf('no-drag') === -1;
        },
        onEnd: ({ oldIndex, newIndex }) => {
          if (oldIndex !== undefined && newIndex !== undefined) {
            //未实际移动位置
            if (oldIndex === newIndex) {
              return;
            }
            const newRow = this.data[oldIndex - 1];
            const oldRow = this.data[newIndex - 1];
            this.moveBeforeByProperty(this.data, newIndex - 1, oldIndex - 1);
            this.$emit('sort-row', newRow, oldRow, this.data);
          }
        },
      });
    },
    moveBeforeByProperty(arr, targetIndex, moveIndex) {
      const [removedItem] = arr.splice(moveIndex, 1);
      arr.splice(targetIndex, 0, removedItem);
      return arr;
    },
    getCreateStyle() {
      return {
        position: 'sticky',
        'z-index': 10,
        left: `${this.selection.width}px`,
      };
    },
    getSelectionStyle() {
      if (!this.isFixed) {
        return {};
      }
      return {
        position: 'sticky',
        'z-index': 10,
        left: 0,
      };
    },
    getColStyle(column) {
      if (!this.isFixed || this.fixdColumns[column.prop] === undefined) {
        return { 'text-align': column.align || 'left' };
      }
      const style = {
        'text-align': column.align || 'left',
        position: 'sticky',
        'z-index': 10,
        left: `${this.fixdColumns[column.prop]}px`,
      };
      return style;
    },
    getRowClass(row, rowIndex) {
      if (row.checked) {
        return 'checked-row-bg';
      }

      if (typeof this.rowClassName === 'function') {
        return this.rowClassName({ row, index: rowIndex });
      }
      return this.rowClassName;
    },
    getSelectionClass(row, rowIndex) {
      return this.getRowClass(row, rowIndex) || 'default-col__bg';
    },
    getColClass(row, rowIndex, column) {
      const classArr = [];
      const className = this.getRowClass(row, rowIndex);
      if (className) {
        classArr.push(className);
      } else {
        classArr.push('default-col__bg');
      }
      if (column.fixed && this.isSrcoll) {
        classArr.push('sticky-shadow');
      }
      return classArr.join(' ');
    },
    handleCreate() {
      this.$emit('create');
    },
    toggleCreate(bool) {
      this.isCreate = bool;
    },

    handleSelect(row) {
      this.$emit('select', row);
    },
    toggleRowSelection(row, bool = true) {
      this.data.forEach((item, index) => {
        if (item.id === row.id) {
          row.checked = bool;
          this.data[index] = row;
        }
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.table_body__row {
  height: 36px;
  td {
    padding: 0 8px;
    border-bottom: 1px solid #e8e9e9;
  }
  .default-col__bg {
    background-color: #ffffff;
  }
}
.table_body__row:hover {
  td {
    background: #f6f7f8;
  }
  .handle-span {
    opacity: 1;
  }
}
.checked-row-bg,
.checked-row-bg:hover {
  td {
    background: #e9f2ff;
  }
}

.handle-span {
  opacity: 0;
  vertical-align: middle;
  margin-left: 2px;
  cursor: move;
  font-size: 14px;
  width: 14px;
  height: 19px;
  position: relative;
  color: #6e737b;
  .more-filled {
    position: absolute;
    /* 旋转90度 */
    transform: rotate(90deg);
    top: 1.5px;
    left: 0;
  }
}

.create_row__button {
  display: flex;
  align-items: center;
  margin-left: 36px;

  cursor: pointer;
  color: #216ef2;
}
.create_row:hover {
  background: #f6f7f8;
}

/* 与 Vue.Draggable 类似，可以为拖拽元素添加样式 */
.sortable-ghost {
  opacity: 0.5;
  background: #e0f2f7;
}

// 固定栏遮罩
.sticky-shadow::after {
  content: '';
  position: absolute;
  top: 0;
  right: -6px;
  height: 100%;
  width: 6px;
  background: linear-gradient(to right, rgba(0, 0, 0, 0.1), transparent);
  pointer-events: none;
}
</style>
